package manegement;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import dao.DBFacade;

import bean.BlogBean;

public class BlogManager {
	
	private HashMap<String, PostManager> postsByBlogs;
	
	private HashMap<String, BlogBean> blogs;

	private HashMap<String, List<CreatePostListener>> listeners; //TODO Annoucement 
	
	public BlogManager(String userId) {
		blogs = new HashMap<String, BlogBean>();
		postsByBlogs = new HashMap<String, PostManager>();
		
		BlogBean blog;
		for(Iterator<BlogBean> it = DBFacade.getInstance().getBlogsByUser(userId).iterator(); it.hasNext();){
			blog = it.next();
			blogs.put(blog.getId(), blog);
			postsByBlogs.put(blog.getId(), new PostManager(blog.getId()));
		}
		
	}

	//Blog Operations 
	/**
	 * Add a blog
	 * @param title
	 * @param description
	 * @return blogId
	 * @throws Exception
	 */
	public String createBlog(String owner, String title, String description) throws Exception {
		String blogId = getNewBlogId();
		BlogBean newBlog = new BlogBean(blogId, title, description, owner);
		blogs.put(blogId, newBlog);
		postsByBlogs.put(blogId, new PostManager(blogId));		
		return blogId;
	}
	
	/**
	 * Retrieves a post attribute value
	 * 
	 * @param postID
	 * @param attribute
	 *            - Attribute which you wants to know value
	 * @return attribute value
	 * @throws Exception
	 *             - Throwns exceptions if given att is invalid
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public String getBlogInformation(String blogId, String attribute)
		throws Exception {
		
		attribute.replaceFirst(attribute.substring(0, 1), attribute.substring(0, 1).toUpperCase());
		BlogBean blog = blogs.get(blogId);
		try {
			Class postBeanClass = blog.getClass();
			
			Method thisMethod = postBeanClass.getMethod("get"
					+ attribute, (Class[]) null);

			Object result = thisMethod.invoke(blog,
					(Object[]) null); // we can receive a null
			return result.toString();
		} catch (Exception e) {
			throw new Exception("Atributo Invalido.");
		}
	} 


	
	/**
	 * Modifies the information of the blog passed as parameter
	 * @param attribute
	 * 			- Attribute will be modifies
	 * @param newValue
	 * 			- NewValue will be inserted
	 * @return true 
	 * 			- if the update was completed successfully
	 * 		   false
	 * 			- otherwise 
	 * @throws Exception
	 */
	public boolean changeBlogInformation(String blogId, String attribute, String newValue)
	throws Exception {
		BlogBean blog = blogs.get(blogId);
		if(blog == null)
			throw new Exception("Invalid post id.");
		if(attribute.equals("title")){
			if(newValue == null || newValue.trim().equals(""))
				throw new Exception("Invalid title. Title of post must have text.");
			blog.setTitle(newValue);

		} else if(attribute.equals("description")){
			blog.setDescription(newValue);
		}
		throw new Exception("Invalid attribute.");

	}
	
	public int getNumberOfBlogs(String ownerId){
		int numberOfSubBlogs = 0;
		for(Iterator<BlogBean> it = blogs.values().iterator(); it.hasNext();){
			if(it.next().getOwner().equals(ownerId)){
				numberOfSubBlogs++;
			}
		}
		return numberOfSubBlogs;
	}
	
	/**
	 * Returns the id of sub blog of blog passed as parameter
	 * @param blogId
	 * @param index
	 * @return subBlogId
	 * @throws Exception
	 */
	public String getBlog(String ownerId, int index) throws Exception{
		List<BlogBean> blogsFromId = new ArrayList<BlogBean>();
		BlogBean blog;
		for(Iterator<BlogBean> it = blogs.values().iterator(); it.hasNext();){
			blog = it.next();
			if(it.next().getOwner().equals(ownerId))
				blogsFromId.add(blog);
		}
		return blogsFromId.get(index).getId();
	}
	


	public void deleteBlog(String blogId){

		BlogBean blog;
		for(Iterator<BlogBean> it = blogs.values().iterator(); it.hasNext();){
			blog = it.next();
			if(blog.getOwner().equals(blogId))
				deleteBlog(blog.getId());
		}
		blogs.remove(blogId);
		postsByBlogs.remove(blogId);
		listeners.remove(blogId);
	}

	//SubBlog Operations
	

	/**
	 * Returns the number of sub blogs
	 * @param blogId
	 * @return number of sub blogs
	 * @throws Exception
	 */
	public int getNumberOfSubBlogs(String blogId) throws Exception{
		if(!blogs.containsKey(blogId)){
			throw new Exception("Invalid blog id");
		}
		return getNumberOfBlogs(blogId);
	}

	/**
	 * Returns the number of all sub blogs
	 * @param blogId
	 * @return number of all sub blogs
	 * @throws Exception
	 */
	public int getNumberOfAllSubBlogs(String blogId) throws Exception{
		if(!blogs.containsKey(blogId)){
			throw new Exception("Invalid blog id");
		}
		int numberOfSubBlogs = 0;
		BlogBean blog;
		for(Iterator<BlogBean> it = blogs.values().iterator(); it.hasNext();){
			blog = it.next();
			if(blog.getOwner().equals(blogId)){
				numberOfSubBlogs += 1 + getNumberOfAllSubBlogs(blog.getId());
			}
		}
		return numberOfSubBlogs;
	}
	

	/**
	 * Returns the id of sub blog of blog passed as parameter
	 * @param blogId
	 * @param index
	 * @return subBlogId
	 * @throws Exception
	 */
	public String getSubBlog(String blogId, int index) throws Exception{
		if( !blogs.containsKey(blogId))
			throw new Exception("Invalid blog id");
		List<BlogBean> blogsFromId = new ArrayList<BlogBean>();
		BlogBean blog;
		for(Iterator<BlogBean> it = blogs.values().iterator(); it.hasNext();){
			blog = it.next();
			if(it.next().getOwner().equals(blogId))
				blogsFromId.add(blog);
		}

		return blogsFromId.get(index).getId();
	}

	/**
	 * Returns the number of all posts of blog passed as parameter
	 * @param blogId
	 * @return number of all posts
	 * @throws Exception
	 */
	public int getNumberOfAllPosts(String blogId) throws Exception {
		if(!blogs.containsKey(blogId)){
			throw new Exception("Invalid blog id");
		}
		int numberOfSubBlogs = 0;
		BlogBean blog;
		for(Iterator<BlogBean> it = blogs.values().iterator(); it.hasNext();){
			blog = it.next();
			if(blog.getOwner().equals(blogId)){
				numberOfSubBlogs += getNumberOfAllPosts(blog.getId());
			}
		}
		numberOfSubBlogs += getNumberOfPosts(blogId);
		return numberOfSubBlogs;
	}
	
	
	//Post Operations
	/**
	 * Creare a new post
	 * @param sessionId
	 * @param blogId
	 * @param title
	 * @param text
	 * @return postId
	 * @throws Exception
	 */
	public String createPost(String blogId, String title, String text, String date) throws Exception {
		if(!postsByBlogs.containsKey(blogId))
			throw new Exception("Invalid blog id.");
		String postId = postsByBlogs.get(blogId).createPost(blogId, title, text, date);
		
		//Observer
		for(Iterator<CreatePostListener> it = listeners.get(blogId).iterator(); it.hasNext();){
			it.next().addPostJustCreated(postId);
		}
		return postId;
	
	}


	/**
	 * Retrieves a post attribute value
	 * 
	 * @param postID
	 * @param attribute
	 *            - Attribute which you wants to know value
	 * @return attribute value
	 * @throws Exception
	 *             - Throwns exceptions if given att is invalid
	 */
	public String getPostInformation(String blogId, String postId, String attribute)
		throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getPostInformation(postId, attribute);
		return null;
	} 
	
	/**
	 * Capturing the post with the index passed as parameter
	 * @param blogId
	 * 			- Identifier of the blog which will capture the post
	 * @param index
	 * 			- Post's index
	 * @return postId
	 */

	
	
	public String getPost(String blogId, int index){
		return postsByBlogs.get(blogId).getPost(index);
	
	}

	
	/**
	 * Modifies the information of the post passed as parameter
	 * @param sessionId
	 * 			- Identifier of the session to validate the User logon
	 * @param postId
	 * 			- Identifier of the post modification
	 * @param attribute
	 * 			- Attribute to be modified
	 * @param value
	 * 			- Value that will be inserted
	 * @throws Exception
	 */
	public void changePostInformation(String blogId, String postId,
			String attribute, String value) throws Exception {
		
		if(postsByBlogs.containsKey(blogId))
			postsByBlogs.get(blogId).changePostInformation(postId, attribute, value);
	}

	/**
	 * Delete a post
	 * @param sessionId
	 * 			- Identifier of the session to validate the User logon
	 * @param postId
	 * 			- Identifier of the post will be deleted 
	 * @throws Exception
	 */
	public void deletePost(String blogId, String postId) {
		if(postsByBlogs.containsKey(blogId))
			postsByBlogs.get(blogId).deletePost(postId);
	}
	
	/**
	 * Returns the number of blog posts
	 * @param blogId
	 * @return number of posts
	 * @throws Exception
	 */
	public int getNumberOfPosts(String blogId) throws Exception{
		if(!postsByBlogs.containsKey(blogId)){
			throw new Exception("Invalid blog id.");
		}
		return postsByBlogs.get(blogId).getNumberOfPosts();
	}


	//Media operations
	/**
	 * Attaches a sound
	 * @param sessionID
	 * 			- Identifier of the session to validate the User logon
	 * @param postID
	 * 			- Identifier of the post that will be inserted audio
	 * @param description
	 * 			- Sound's description
	 * @param data
	 * 			- Data's sound
	 * @return soundId
	 *          - Identifier of the sound
	 * @throws Exception
	 */
	public String attachSound(String blogId, String postID,
			String description, String data) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).attachSound(postID, description, data);
		return null;
	}

	/**
	 * Attaches a movie
	 * @param sessionID
	 * 			- Identifier of the session to validate the User logon
	 * @param postID
	 * 			- Identifier of the post that will be inserted sound
	 * @param description
	 * 			- Movie's description
	 * @param data
	 * 			- Data's movie
	 * @return moviedId
	 *          - Identifier of the movie
	 * @throws Exception
	 */
	public String attachMovie(String blogId, String postID,
			String description, String data) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).attachSound(postID, description, data);
		return null;
	}


	/**
	 * Attaches a picture
	 * @param sessionID
	 * 			- Identifier of the session to validate the User logon
	 * @param postID
	 * 			- Identifier of the post that will be inserted picture
	 * @param description
	 * 			- Picture's description
	 * @param data
	 * 			- Data's picture
	 * @return pictureId
	 *          - Identifier of the picture
	 * @throws Exception
	 */
	public String attachPicture(String blogId, String postID,
			String description, String data) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).attachSound(postID, description, data);
		return null;
	}
	
	/**
	 * Delete a movie
	 * @param sessionId
	 * 			- Identifier of the session to validate the User logon
	 * @param movieId
	 * 			- Identifier of the movie will be deleted
	 */
	public void deleteMovie(String blogId, String postId, String movieId) {
		if(postsByBlogs.containsKey(blogId))
			postsByBlogs.get(blogId).deleteMovie(postId, movieId); 
		}
	
	/**
	 * Delete a sound
	 * @param sessionId
	 * 			- Identifier of the session to validate the User logon
	 * @param soundId
	 * 			- Identifier of the sound will be deleted
	 */
	public void deleteSound(String blogId, String postId, String soundId) {
		if(postsByBlogs.containsKey(blogId))
			postsByBlogs.get(blogId).deleteSound(postId, soundId); 
		
	}

	/**
	 * Delete a picture
	 * @param sessionId
	 * 			- Identifier of the session to validate the User logon
	 * @param pictureId
	 * 			- Identifier of the picture will be deleted
	 */
	public void deletePicture(String blogId, String postId, String pictureId) {
		if(postsByBlogs.containsKey(blogId))
			postsByBlogs.get(blogId).deletePicture(postId, pictureId); 

	}


	/**
	 * Returns the number of sounds from post
	 * @param postId
	 * 			- Identifier of the post sounds to be counted
	 * @return number of sounds
	 * @throws Exception
	 */
	public int getNumberOfSoundsOfPost(String blogId, String postId) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getNumberOfSoundsOfPost(postId);
		return 0;
		}

	/**
	 * Returns the number of pictures from post
	 * @param postId
	 * 			- Identifier of the post pictures to be counted
	 * @return number of pictures
	 * @throws Exception
	 */
	public int getNumberOfPicturesOfPost(String blogId, String postId) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getNumberOfPicturesOfPost(postId);
		return 0;	
		}
	
	/**
	 * Returns the number of movies from post
	 * @param postId
	 * 			- Identifier of the post movies to be counted
	 * @return number of movies
	 * @throws Exception
	 */
	public long getNumberOfMoviesOfPost(String blogId, String postId) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getNumberOfPicturesOfPost(postId);
		return 0;			
	}
	
	/**
	 * Capturing the sound of the post with the index passed as parameter
	 * @param postId
	 * 			- Identifier of the post which will capture the sound
	 * @param index
	 * 			- Sound's index
	 * @return soundId
	 * @throws Exception
	 */
	public String getSound(String blogId, String postId, int index) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getSound(postId, index);
		return "";				
	}
	
	/**
	 * Capturing the movie of the post with the index passed as parameter
	 * @param postId
	 * 			- Identifier of the post which will capture the movie
	 * @param index
	 * 			- Movie's index
	 * @return movieId
	 * @throws Exception
	 */
	public String getMovie(String blogId, String postId, int index) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getMovie(postId, index);
		return "";				
	}
	
	/**
	 * Capturing the picture of the post with the index passed as parameter
	 * @param postId
	 * 			- Identifier of the post which will capture the picture
	 * @param index
	 * 			- Picture's index
	 * @return pictureId
	 * @throws Exception
	 */
	public String getPicture(String blogId, String postId, int index) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getMovie(postId, index);
		return "";		
	}

	
	/**
	 * Returns data of sound
	 * @param soundId
	 * @return data of sound
	 * @throws Exception 
	 */
	public String getSoundData(String blogId, String postId, String mediaId) throws Exception{
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getSoundData(postId, mediaId);
		return "";	
	}
	
	/**
	 * Returns description of sound
	 * @param soundId
	 * @return description of sound
	 * @throws Exception 
	 */
	public String getSoundDescription(String blogId, String postId, String mediaId) throws Exception{
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getSoundDescription(postId, mediaId);
		return "";	
	}
	
	/**
	 * Returns data of picture
	 * @param picture Id
	 * @return data of picture
	 * @throws Exception 
	 */
	public String getPictureData(String blogId, String postId, String mediaId) throws Exception{
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getPictureData(postId, mediaId);
		return "";	

	}
	
	/**
	 * Returns description of picture
	 * @param pictureId
	 * @return description of picture
	 * @throws Exception 
	 */
	public String getPictureDescription(String blogId, String postId, String mediaId) throws Exception{
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getPictureDescription(postId, mediaId);
		return "";	

	}
	
	/**
	 * Returns data of movie
	 * @param movie Id
	 * @return data of movie
	 * @throws Exception 
	 */
	public String getMovieData(String blogId, String postId, String mediaId) throws Exception{
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getMovieData(postId, mediaId);
		return "";		
	}
	
	/**
	 * Returns description of movie
	 * @param movieId
	 * @return description of movie
	 * @throws Exception 
	 */
	public String getMovieDescription(String blogId, String postId, String mediaId) throws Exception{
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getMovieDescription(postId, mediaId);
		return "";	}

	//Comment Operations
	/**
	 * Add a comment
	 * @param postId
	 * 			- identifier of the post which is inserted into the comment
	 * @param comment
	 * 			- Text's comment
	 * @return
	 * @throws Exception
	 */
	public String addComment(String blogId, String postId, String comment, String login) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).addComment(postId, comment, login);
		return "";		
		
	}
	


	/**
	 * Returns the number of comments of post
	 * @param postId
	 * 			- Identifier of the post which will capture the number of comments
	 * @return number of posts
	 * @throws Exception
	 */
	public int getNumberOfComments(String blogId, String postId) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getNumberOfComments(postId);
		return 0; 
	}

	
	/**
	 * Capturing the comment with the index passed as parameter
	 * @param postId
	 * 			- Identifier of the post which will capture the comment
	 * @param index
	 * 			- comment's index
	 * @return commentId
	 */
	public String getComment(String blogId, String postId, int index) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getComment(postId, index);
		return "";
	}
	
	/**
	 * Retrieves the comment's text passed as parameter
	 * @param commentId
	 * 			- identifier of the comment that the text will be recovered
	 * @return comment's text
	 * @throws Exception
	 */
	public String getCommentText(String blogId, String postId, String commentId) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getCommentText(postId, commentId);
		return "";
		
	}

	/**
	 * Retrieves the comment's author passed as parameter
	 * @param commentId
	 * 			- identifier of the comment that the author will be recovered
	 * @return comment's author
	 * @throws Exception
	 */
	public String getCommentAuthor(String blogId, String postId, String commentId) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getCommentAuthor(postId, commentId);
		return "";		
	}

	public String addSubComment(String blogId, String postId, String commentId, String text, String login) throws Exception{
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).addSubComment(postId, commentId, text, login);
		return "";
	}

	public String getSubComment(String blogId, String postId, String commentId, int index) throws Exception {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getSubComment(postId, commentId, index);
		return "";
	}

	public int getNumberOfSubComments(String blogId, String postId, String commentId) throws Exception{
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getNumberOfSubComments(postId, commentId);
		return 0;		
	}

	public int getNumberOfAllSubComments(String blogId, String postId, String commentId) {
		if(postsByBlogs.containsKey(blogId))
			return postsByBlogs.get(blogId).getNumberOfAllSubComments(postId, commentId);
		return 0;		
		
	}

	public int getNumberOfCommentsByLogin(String blogId, String login) {
		return postsByBlogs.get(blogId).getNumberOfCommentsByLogin(login);
	}

	public List<String> findBlogByName(String match) {
		List<String> blogsForSearch = new ArrayList<String>();
		BlogBean blog;
		for(Iterator<BlogBean> it = blogs.values().iterator(); it.hasNext();){
			blog = it.next();
			if(blog.getTitle().toUpperCase().contains(match.toUpperCase()))
				blogsForSearch.add(blog.getId());
		}
		return blogsForSearch;
	}

	public void save(){
		DBFacade.getInstance().saveBlogs(blogs.values());
	}
	
	private String getNewBlogId() {
		return String.valueOf(DBFacade.getInstance().getLastBlogId());
	}




}
